1

Gin路由主要流程实现

经过上一篇的学习笔记,我们已经知道了Gin router的主要流程。但是我们看到代码和方法体总体很长,其中大部分是参数路由的判断。这些零散的小逻辑,让我们阅读源码的时候更难理解了一些。但是其实基数树的逻辑兵没有这么的复杂,所以我们还是按照老规矩,自己实现以下这个简单的基数树值包含主流程。代码如下:

package mygin

import "fmt"

type Trees map[string]*node

type node struct {
    path     string
    indices  string
    children []*node
    handlers HandlerList
}

func (n *node) addRoute(path string, handlers HandlerList) {
    if len(n.path) > 0 || len(n.children) > 0 {
    walk:
        for {
            //找到相等的index
            i := 0
            max := min(len(path), len(n.path))
            for max > i && path[i] == n.path[i] {
                i++
            }
            //需要把原来的作为子node放到新node中
            if i < len(n.path) {
                //新建node
                child := node{
                    path:     n.path[i:],
                    indices:  n.indices,
                    handlers: n.handlers,
                    children: n.children,
                }

                n.children = []*node{&child}
                n.indices = string([]byte{n.path[i]})
                n.path = path[:i]
                n.handlers = nil
            }
            // 判断子节点如果有相同开头的字符 则从新跳入循环
            if i < len(path) {
                c := path[i]
                for index := 0; index < len(n.indices); index++ {
                    if c == n.indices[index] {
                        n = n.children[index]
                        path = path[i:]
                        continue walk
                    }
                }

                //把新请求的path加入到router中
                n.insertChild(path[i:], path, handlers, i)
                return
            }
            return
        }
    } else {
        //如果为空
        n.path = path
        n.handlers = handlers
    }
}

func (n *node) insertChild(path, fullPath string, handlers HandlerList, index int) {
    child := node{}
    child.handlers = handlers
    child.indices = ""
    child.path = path
    n.indices += string([]byte{fullPath[index]})
    n.children = append(n.children, &child)
}

func min(a, b int) int {
    if a > b {
        return b
    }

    return a
}

func (n *node) getValue(path string) (handlers HandlerList) {
    index := 1
walk:
    for {
        fmt.Println("loop num: ", index)
        if len(path) > len(n.path) {
            path = path[len(n.path):]
            c := path[0]
            for i := 0; i < len(n.indices); i++ {
                if c == n.indices[i] {
                    n = n.children[i]
                    index++
                    goto walk
                }
            }
        } else if len(path) == len(n.path) {
            handlers = n.handlers
            return
        }
    }
}

总结

上面的代码已经不需要太多的注释了,去掉了参数节点的代码整个流程已经很明确了。

结束语

Gin的源码学习和分析已经全部结束了。其实对于Gin框架源码的分析已经有了很多文章,但是如果在学习的同时自己也简单的模仿和实现一下这些功能对于我们理解就更有帮助。
Gin是一个十分轻巧http框架,代码也十分的简介和清楚。实现也有一些亮点,我觉得很适合新手对于go源码学习和分析的入门框架。希望这5篇文章能对在学习go中的人有一些帮助。


大二小的宝
222 声望74 粉丝